import { hexToBigint } from "./utils";

export type Hex = `0x${string}`;

export class Provider {
  constructor(public url: string) {}

  async call<T>(method: string, params: unknown[]): Promise<T> {
    const res = await fetch(this.url, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
    });
    if (!res.ok) throw new Error(`RPC失败: ${res.status} ${res.statusText}`);
    const j = await res.json();
    if (j.error) throw new Error(`RPC错误: ${JSON.stringify(j.error)}`);
    return j.result as T;
  }

  async chainId(): Promise<number> {
    const id = await this.call<string>("eth_chainId", []);
    return Number(hexToBigint(id));
  }

  async nonce(address: string): Promise<bigint> {
    const n = await this.call<string>("eth_getTransactionCount", [address, "latest"]);
    return hexToBigint(n);
  }

  async balance(address: string): Promise<bigint> {
    const b = await this.call<string>("eth_getBalance", [address, "latest"]);
    return hexToBigint(b);
  }

  async baseFeePerGas(): Promise<bigint> {
    const blk = await this.call<any>("eth_getBlockByNumber", ["latest", false]);
    return hexToBigint(blk.baseFeePerGas);
  }

  async maxPriorityFeePerGas(): Promise<bigint> {
    try {
      const tip = await this.call<string>("eth_maxPriorityFeePerGas", []);
      return hexToBigint(tip);
    } catch {
      // 回退到2 gwei
      return 2n * 10n ** 9n;
    }
  }

  async estimateGas(call: { from?: string; to?: string; value?: Hex; data?: Hex }): Promise<bigint> {
    const gas = await this.call<string>("eth_estimateGas", [call]);
    return hexToBigint(gas);
  }

  async sendRawTransaction(raw: Hex): Promise<string> {
    return await this.call<string>("eth_sendRawTransaction", [raw]);
  }

  async getTransactionReceipt(hash: string): Promise<any | null> {
    return await this.call<any | null>("eth_getTransactionReceipt", [hash]);
  }
}